import json
import time

import cv2
import numpy
import win32api
import win32con
import win32gui
import win32print
import win32ui


class Window:
    def __init__(self, name, cls=None):
        hDesktopDC = win32gui.GetDC(0)
        self.scale = win32print.GetDeviceCaps(hDesktopDC, win32con.DESKTOPHORZRES) \
                     / win32print.GetDeviceCaps(hDesktopDC, win32con.HORZRES)
        win32gui.ReleaseDC(None, hDesktopDC)

        self.hWnd = win32gui.FindWindow(cls, name)
        assert self.hWnd
        self.hWndDC = win32gui.GetDC(self.hWnd)
        self.hMfcDc = win32ui.CreateDCFromHandle(self.hWndDC)
        self.hMemDc = self.hMfcDc.CreateCompatibleDC()

    def capture(self):
        width, height = [round(i * self.scale)
                         for i in win32gui.GetClientRect(self.hWnd)[2:]]
        hBmp = win32ui.CreateBitmap()
        hBmp.CreateCompatibleBitmap(self.hMfcDc, width, height)
        self.hMemDc.SelectObject(hBmp)
        self.hMemDc.BitBlt((0, 0), (width, height),
                           self.hMfcDc, (0, 0), win32con.SRCCOPY)
        result = numpy.frombuffer(hBmp.GetBitmapBits(
            True), dtype='uint8').reshape(height, width, 4)[..., :3]
        win32gui.DeleteObject(hBmp.GetHandle())
        return result

    def click(self, hold=0):
        win32api.PostMessage(self.hWnd, win32con.WM_LBUTTONDOWN, 0, 0)
        time.sleep(hold)
        win32api.PostMessage(self.hWnd, win32con.WM_LBUTTONUP, 0, 0)

    def __del__(self):
        self.hMemDc.DeleteDC()
        self.hMfcDc.DeleteDC()
        win32gui.ReleaseDC(self.hWnd, self.hWndDC)


window = Window('原神')

IMG_STOP = cv2.imread('image/stop.png')


# READY = cv2.imread('image/ready.png')
# READYMASK = cv2.imread('image/readymask.png')
# FRONT = cv2.imread('image/front.png')
# FRONTMASK = cv2.imread('image/frontmask.png')
# BACK = cv2.imread('image/back.png')
# BACKMASK = cv2.imread('image/backmask.png')
# CUR = cv2.imread('image/cur.png')
# CURMASK = cv2.imread('image/curmask.png')


class Check:
    def __init__(self, im=None):
        self.im = cv2.resize(window.capture() if im is None else im, (1280, 720))

    def isReady(self, d=.045):
        # return .05 > \
        # 越小误差越小
        return d > \
               cv2.minMaxLoc(cv2.matchTemplate(self.im[130:155, 588:685], READY, cv2.TM_SQDIFF_NORMED, mask=READYMASK))[
                   0]

    def getPos(self):
        loc = cv2.minMaxLoc(cv2.matchTemplate(
            self.im[57:96, 470:810], CUR, cv2.TM_SQDIFF_NORMED, mask=CURMASK))
        if loc[0] > .05:
            return None
        return (
            cv2.minMaxLoc(cv2.matchTemplate(
                self.im[57:96, 470:810], FRONT, cv2.TM_SQDIFF_NORMED, mask=FRONTMASK))[2][0],
            cv2.minMaxLoc(cv2.matchTemplate(
                self.im[57:96, 470:810], BACK, cv2.TM_SQDIFF_NORMED, mask=BACKMASK))[2][0],
            loc[2][0]
        )


with open('config.json') as f:
    config = json.load(f)


# if __name__ == '__main__':
def m():
    print('initialized')

    while True:
        # if config['startKey']:
        #     while win32api.GetKeyState(config['startKey']) >= 0:
        #         time.sleep(.05)
        time.sleep(.05)
        print('wait')
        while not Check().isReady(.04):
            time.sleep(.05)
        print('start')
        # first=True
        window.click(0.01)
        print('go')

        totalTime = 0
        missTime = 0

        s_time = time.time()

        while True:
            # 已经进入钓鱼状态
            pos = Check().getPos()
            if pos is None:
                break
            totalTime += 1

            front, back, cur = pos
            if front >= back:
                continue
            buf = ['['] + [' '] * 34 + [']']
            buf[front // 10 + 2] = '<'
            buf[back // 10 + 2] = '>'
            buf[cur // 10 + 2] = '|'
            print(''.join(buf), end='\r')
            # if cur + 10 < (back + front) // 2:
            mid = (back + front) // 2
            dif = 0
            now = cur + 0
            length = back - front

            if length < 20:
                continue

            if not (front <= now <= back):
                if front > now:
                    # 力度不够为负数
                    dif = now - front
                elif back < now:
                    # 力大了为正数
                    dif = now - back
                missTime += 1

            # if dif != 0:
            #     print(dif)

            # if now < mid:
            if True:

                if dif == 0:
                    # 在范围内
                    rate = (now - front) / length
                    # if now - front > 7 and back - front < 15:
                    #     time.sleep(0.002 * (back - now))
                    if rate < 0.2:
                        window.click(0.02)
                    elif rate > 0.4:
                        time.sleep(0.4 * rate)
                        # window.click(0.01)
                    elif rate > 0.75:
                        time.sleep(rate * 0.2)
                        # window.click(0.005)
                        continue
                        # pass
                elif dif < 0:
                    # 力度不够
                    # 离得越近间隔越大，反之间隔越小
                    if dif < 4:
                        # pass
                        window.click(0.02)
                        # time.sleep(0.002 * abs(2 - dif))
                    elif dif > 4:
                        num = dif // 20
                        for i in range(num):
                            window.click(0.01)
                            time.sleep(0.001)
                        window.click(0.015)
                elif dif > 0:
                    # （ dif > 0 ）
                    # 力度太大了
                    time.sleep(0.015 * abs(dif) + 0.01)
                    # window.click(0.02)

                # if not (front <= now <= back):
                    # print("(now,front, back, mid, length, dif)")
                    # print((now, front, back, mid, length, dif))

        print(' ' * 36, end='\r')
        if totalTime != 0 and missTime == 0:
            print("-> Perfect!!! <-")
        elif totalTime > 0:
            print(round(missTime * 100 / totalTime, 2), "%")
        print('Ok!')

        e_time = time.time()
        time_taken_in_micro = (e_time - s_time) * (10 ** 6)
        print("时长：{0} s".format(round(time_taken_in_micro / 1000, 0)))
        print("-" * 10)


m()
